package com.gitee.stream;

import com.alibaba.fastjson.JSONObject;
import com.gitee.stream.cart.CartService;
import com.gitee.stream.cart.Sku;
import com.gitee.stream.cart.SkuCategoryEnum;
import org.checkerframework.checker.units.qual.min;
import org.junit.Before;
import org.junit.Test;

import java.util.*;

/**
 * 演示流的各种操作
 *
 * @author gcq
 * @Create 2022-06-30
 */
public class StreamOperator {

    List<Sku> list;

    @Before
    public void init() {
        list = CartService.getCartSkuList();
    }

    /**
     * filter使用: 过滤掉不符合断言判断的数据
     * <p>
     * Predicate 接收一个参数 返回一个 boolean 结果
     */
    @Test
    public void filterTest() {
        list.stream()
                .filter(sku -> SkuCategoryEnum.BOOKS.equals(sku.getSkuCategory()))
                .forEach(item -> System.out.println(JSONObject.toJSONString(item, true)));
    }

    /**
     * map使用: 将一个元素转换成另一个元素
     * Function 接收一个对象 转换成另一个对象
     */
    @Test
    public void mapTest() {
        list.stream()
                .map(sku -> sku.getSkuName())
                .forEach(item -> System.out.println(JSONObject.toJSONString(item, true)));
    }

    /**
     * flatMap使用: 将一个对象转换成流
     */
    @Test
    public void flatMapTest() {
        list.stream()
                .flatMap(sku -> Arrays.stream(sku.getSkuName().split("")))
                .forEach(item -> System.out.println(JSONObject.toJSONString(item, true)));
    }

    /**
     * peek使用:
     * 中间操作
     * 此方法的存在主要是为了支持调试，您希望在元素流过管道中的某个点时查看它们
     * 输出流操作时候的值
     */
    @Test
    public void peekTest() {
        list.stream()
                .peek(sku -> System.out.println(sku.getSkuName()))
                .forEach(item -> System.out.println(JSONObject.toJSONString(item, true)));
    }

    /**
     * sort使用: 排序
     * 对流中元素进行排序，可选则自然排序或指定排序规则
     */
    @Test
    public void sortTest() {
        list.stream()
                .peek(sku -> System.out.println(sku.getSkuName()))
                .sorted(Comparator.comparing(Sku::getTotalPrice).reversed())
                .forEach(item -> System.out.println(JSONObject.toJSONString(item, true)));
    }

    /**
     * distinct:对流的元素去重
     */
    @Test
    public void distinctTest() {
        list.stream()
                .map(sku -> sku.getSkuCategory())
                .distinct()
                .forEach(item -> System.out.println(JSONObject.toJSONString(item, true)));
    }

    /**
     * skip:跳过前N条记录
     */
    @Test
    public void skipTest() {
        list.stream()
                .sorted(Comparator.comparing(Sku::getTotalPrice).reversed())
                .skip(3)
                .forEach(item -> System.out.println(JSONObject.toJSONString(item, true)));
    }


    /**
     * limit:只返回前N条数据,有状态操作
     */
    @Test
    public void limitTest() {
        list.stream()
                .sorted(Comparator.comparing(Sku::getTotalPrice).reversed())
                .skip(0 * 3)
                .limit(3)
                .forEach(item -> System.out.println(JSONObject.toJSONString(item, true)));
    }


    /**
     * allMath:所有元素匹配，返回 true
     * 终端操作 短路操作
     * 匹配后，不往后继续执行
     */
    @Test
    public void allMathTest() {
        boolean allMath = list.stream()
                .peek(sku -> System.out.println(JSONObject.toJSONString(sku, true)))
                .allMatch(sku -> sku.getTotalPrice() > 100);
        System.out.println(allMath);
    }

    /**
     * anyMath: 任何元素匹配，返回 true
     */
    @Test
    public void anyMatchTest() {
        boolean anyMatch = list.stream()
                .peek(sku -> System.out.println(JSONObject.toJSONString(sku, true)))
                .anyMatch(sku -> sku.getTotalPrice() > 100);
        System.out.println(anyMatch);
    }

    /**
     * noneMatch: 任何元素都不匹配，返回 true
     */
    @Test
    public void noneMatchTest() {
        boolean noneMatch = list.stream()
                .peek(sku -> System.out.println(JSONObject.toJSONString(sku, true)))
                .noneMatch(sku -> sku.getTotalPrice() > 700);
        System.out.println(noneMatch);
    }

    /**
     * findFirst: 返回流中第一个元素
     */
    @Test
    public void findFirstTest() {
        Optional<Sku> first = list.stream()
                .findFirst();
        System.out.println(JSONObject.toJSONString(first.get(), true));
    }

    /**
     * findAny: 返回流中一个元素
     */
    @Test
    public void findAnyTest() {
        Optional<Sku> first = list.stream()
                .findAny();
        System.out.println(JSONObject.toJSONString(first.get(), true));
    }

    /**
     * max: 返回流中最大结果
     */
    @Test
    public void maxTest() {
        OptionalDouble max = list.stream()
                // 获取总价
                .mapToDouble(Sku::getTotalPrice)
                .max();
        System.out.println(max.getAsDouble());
    }

    /**
     * min:返回流中最小结果
     */
    @Test
    public void minTest() {
        OptionalDouble min = list.stream()
                // 获取总价
                .mapToDouble(Sku::getTotalPrice)
                .min();
        System.out.println(min.getAsDouble());
    }


    /**
     * count:返回流中元素数量
     */
    @Test
    public void countTest() {
        long count = list.stream()
                .count();
        System.out.println(count);
    }

    /**
     * reduce
     * link https://blog.csdn.net/lijingronghcit/article/details/108348728
     */
    @Test
    public void reduceTest() {
        double d = list.stream()
                .map(sku -> sku.getTotalPrice())
                .reduce(0d, (s, e) -> s + e);
        System.out.println(d);
    }
}